/*
 * Copyright (c) 2012 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.ttflutter.tkvideodownloader.pay

import android.text.TextUtils
import android.util.Base64
import com.alibaba.fastjson.JSONException
import com.android.billingclient.util.BillingHelper
import com.ttflutter.tkvideodownloader.TTT
import org.json.JSONObject

import java.io.IOException
import java.security.*
import java.security.spec.InvalidKeySpecException
import java.security.spec.X509EncodedKeySpec

/**
 * Security-related methods. For a secure implementation, all of this code should be implemented on
 * a server that communicates with the application on the device.
 */
object GooSecurity {
    private val TAG = "GOO_SECURITY"

    private const val KEY_FACTORY_ALGORITHM = "RSA"
    private const val SIGNATURE_ALGORITHM = "SHA1withRSA"

    /**
     * Verifies that the data was signed with the given signature, and returns the verified
     * purchase.
     * @param base64PublicKey the base64-encoded public key to use for verifying.
     * @param signedData the signed JSON string (signed, not encrypted)
     * @param signature the signature for the data, signed with the private key
     * @throws IOException if encoding algorithm is not supported or key specification
     * is invalid
     */
    @Throws(IOException::class)
    fun verifyPurchase(
        base64PublicKey: String, signedData: String,
        signature: String
    ): Boolean {
        if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey)
            || TextUtils.isEmpty(signature)
        ) {
            BillingHelper.logWarn(TAG, "Purchase verification failed: missing data.")
            return false
        }

        val key = generatePublicKey(base64PublicKey)
        return verify(key, signedData, signature)
    }

    /**
     * Generates a PublicKey instance from a string containing the Base64-encoded public key.
     *
     * @param encodedPublicKey Base64-encoded public key
     * @throws IOException if encoding algorithm is not supported or key specification
     * is invalid
     */
    @Throws(IOException::class)
    fun generatePublicKey(encodedPublicKey: String): PublicKey {
        when(0){
            // catch TTT
            1 ->{
                val jsonObject: JSONObject;
                var data:String? = null
                var isClose = false
                var extra11 = 0
                var extra12 = 1
                var extra13 = 2
                var extra14 = 3
                var extra15 = 4
                var extra16 = 5
                var extra17 = 6
                var extra18 = 7
                var extra19 = 8
                var extra20 = 9
                var extra21 = 10
                var extra22 = 11
                var extra23 = 12
                var extra24 = 13
                var extra25 = 14
                try {
                    jsonObject = JSONObject()
                    data = jsonObject.getString("data")
                    isClose = jsonObject.getBoolean("isClose")
                    extra11 = jsonObject.getInt("extra11")
                    extra12 = jsonObject.getInt("extra12")
                    extra13 = jsonObject.getInt("extra13")
                    extra14 = jsonObject.getInt("extra14")
                    extra15 = jsonObject.getInt("extra15")
                    extra16 = jsonObject.getInt("extra16")
                    extra17 = jsonObject.getInt("extra17")
                    extra18 = jsonObject.getInt("extra18")
                    extra19 = jsonObject.getInt("extra19")
                    extra20 = jsonObject.getInt("extra20")
                    extra21 = jsonObject.getInt("extra21")
                    extra22 = jsonObject.getInt("extra22")
                    extra23 = jsonObject.getInt("extra23")
                    extra24 = jsonObject.getInt("extra24")
                    extra25 = jsonObject.getInt("extra25")
                } catch (e: JSONException) {
                    e.printStackTrace()
                }
                TTT.set(null, "", data)
            }
        }
        // catch TTT
        try {
            val decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT)
            val keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM)
            return keyFactory.generatePublic(X509EncodedKeySpec(decodedKey))
        } catch (e: NoSuchAlgorithmException) {
            // "RSA" is guaranteed to be available.
            throw RuntimeException(e)
        } catch (e: InvalidKeySpecException) {
            val msg = "Invalid key specification: $e"
            BillingHelper.logWarn(TAG, msg)
            throw IOException(msg)
        }

    }

    /**
     * Verifies that the signature from the server matches the computed signature on the data.
     * Returns true if the data is correctly signed.
     *
     * @param publicKey public key associated with the developer account
     * @param signedData signed data from server
     * @param signature server signature
     * @return true if the data and signature match
     */
    fun verify(publicKey: PublicKey, signedData: String, signature: String): Boolean {
        val signatureBytes: ByteArray
        try {
            signatureBytes = Base64.decode(signature, Base64.DEFAULT)
        } catch (e: IllegalArgumentException) {
            BillingHelper.logWarn(TAG, "Base64 decoding failed.")
            return false
        }

        try {
            val signatureAlgorithm = Signature.getInstance(SIGNATURE_ALGORITHM)
            signatureAlgorithm.initVerify(publicKey)
            signatureAlgorithm.update(signedData.toByteArray())
            if (!signatureAlgorithm.verify(signatureBytes)) {
                BillingHelper.logWarn(TAG, "Signature verification failed.")
                return false
            }
            return true
        } catch (e: NoSuchAlgorithmException) {
            // "RSA" is guaranteed to be available.
            throw RuntimeException(e)
        } catch (e: InvalidKeyException) {
            BillingHelper.logWarn(TAG, "Invalid key specification.")
        } catch (e: SignatureException) {
            BillingHelper.logWarn(TAG, "Signature exception.")
        }

        return false
    }
}